﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
//using EMF;
using System.Windows.Forms;
using System.Threading;
using PrinterMasterClient;
using PrinteMaster;
namespace PrinterMasterClient
{
    /// <summary>
    /// @leopard
    /// 2017年6月11日19:39:38
    /// c#用api太鸡巴蛋疼了，操作打印机的代码见c++代码。
    /// </summary>
    class PrinterAPI
    {
        /// <summary>
        /// 静态实例变量，等价于 PrinterAPI.getInstance()
        /// 该函数可以获取到唯一的，合法的PrinterAPI的值。
        /// 你可以使用 enumJobs()和enumPrinter()来获取到所有的打印机和作业列表
        /// 在枚举过一次以后，你也可以直接使用 getPrinterQueues()和getJobQueues()来取到上一次枚举的结果。
        /// </summary>
        public static PrinterAPI m_PrinterAPI = new PrinterAPI();
        /// <summary>
        /// 静态函数，等价于 PrinterAPI.m_PrinterAPI.
        /// 该函数可以获取到唯一的，合法的PrinterAPI的值。
        /// 你可以使用 enumJobs()和enumPrinter()来获取到所有的打印机和作业列表
        /// 在枚举过一次以后，你也可以直接使用 getPrinterQueues()和getJobQueues()来取到上一次枚举的结果。
        /// </summary>
        /// <returns></returns>
        public static PrinterAPI getInstance() { return m_PrinterAPI; }

        public static List<PrinterInfo> m_PrinterQueues = new List<PrinterInfo>();
        public static List<PrinterInfo> getPrinterQueues() { return m_PrinterQueues; }

        public enum Error
        {
            /// <summary>
            /// 需要删除的jobid不存在
            /// </summary>
            noneJobId,
            /// <summary>
            /// 单次打印任务中，只能选择一台打印机.
            /// </summary>
            onlyOnePrinter,
            /// <summary>
            /// 数据库错误
            /// </summary>
            dataBase,
            /// <summary>
            /// 获取正确
            /// </summary>
            ok,
            /// <summary>
            /// win32api底层报错
            /// </summary>
            API,
            /// <summary>
            /// 数据封送报错
            /// </summary>
            menory,
            /// <summary>
            /// 打开打印机句柄时报错
            /// </summary>
            openPrinter,
            /// <summary>
            /// 枚举打印机时报错
            /// </summary>
            enumPrinter,
            /// <summary>
            /// 枚举作业列表时报错
            /// </summary>
            enumJobs,
            /// <summary>
            /// 用户所选的打印机无效
            /// </summary>
            printerInvalid,
            /// <summary>
            /// 设置打印机时出错
            /// </summary>
            setJob,
            /// <summary>
            /// 
            /// </summary>
            getPrinter,
            /// <summary>
            /// 打印机状态异常
            /// </summary>
            printerState
        }
        /// <summary>
        /// 记录了打印机信息结构，包含了名字，打印机核心名，状态以及端口号
        /// </summary>
        public class PrinterInfo
        {
            public IntPtr handle = IntPtr.Zero;
            public string name = "";
            public string processName = "";
            public uint state = 0;
            public string protName = "";
        }
        
        public int m_PrinterValue = 0;
        public int[] jobIds = new int[1024];
        public int lpThisjobIds = 0;
        /// <summary>
        /// 枚举所有系统的本地打印机和网络打印机。
        /// </summary>
        /// <param name="lastError"></param>
        /// <returns></returns>
        public Error enumPrinter(out uint lastError)
        {
            // 打印机不是队列变量.
            getPrinterQueues().Clear();
            lastError = 0;
            bool Success;
            int cbRequired;
            int nEntries;
            IntPtr outb = IntPtr.Zero;
            ///////////////////
            // 枚举打印机
            Success = Win32Api.EnumPrinters(Win32Api.PRINTER_ENUM_LOCAL, null, 2, outb, 0, out cbRequired, out nEntries);
            outb = Marshal.AllocHGlobal(cbRequired);
            Success = Win32Api.EnumPrinters(Win32Api.PRINTER_ENUM_LOCAL, null, 2, outb, cbRequired, out cbRequired, out nEntries);
            if (!Success)
            {
                lastError = Win32Api.GetLastError();
                return Error.enumPrinter;
            }
            Win32Api.PRINTER_INFO_2[] portsArray = new Win32Api.PRINTER_INFO_2[nEntries];
            IntPtr current = outb;
            m_PrinterValue = nEntries;
            //////////////////
            // 封送内存数据到结构体
            for (int i = 0; i < nEntries; i++)
            {
                try
                {
                    PrinterInfo p = new PrinterInfo();
                    portsArray[i] = (Win32Api.PRINTER_INFO_2)Marshal.PtrToStructure(current,
                     typeof(Win32Api.PRINTER_INFO_2));
                    current = (IntPtr)(current.ToInt64() + Marshal.SizeOf(typeof(Win32Api.PRINTER_INFO_2)));
                    p.name = portsArray[i].pPrinterName;
                    p.processName = portsArray[i].pPrintProcessor;
                    p.state = portsArray[i].Status;
                    p.protName = portsArray[i].pPortName;
                    getPrinterQueues().Add(p);

                }
                catch (Exception ex) { Console.Write(ex.Message); return Error.menory; }
            }
            Marshal.FreeHGlobal(outb);
            return Error.ok;
        }
        /// <summary>
        /// 获取打印机的状态
        /// </summary>
        /// <param name="printerName">打印机名</param>
        /// <param name="lastError"></param>
        /// <param name="stateStr">打印机错误的字符串list</param>
        /// <param name="state">win32api返回的state码，通过与自身取按位与，然后与自身比较获得位标识</param>
        /// <returns></returns>
        public Error getPrinterState(string printerName, out uint lastError, out List<string> stateStr, out int state)
        {
            stateStr = new List<string>(); state = 0; lastError = 0;
            bool Success;
            IntPtr outb = IntPtr.Zero;
            IntPtr handle;
            uint pwNeeded = 0;
            Win32Api.OpenPrinter(printerName, out handle, Win32Api.NULL);
            if (handle == Win32Api.NULL)
            {
                lastError = Win32Api.GetLastError();
                return Error.openPrinter;
            }
            Success = Win32Api.GetPrinter(handle, 2, Win32Api.NULL, 0, out pwNeeded);
            if (pwNeeded == 0)
            {
                lastError = Win32Api.GetLastError();
                return Error.getPrinter;
            }
            // 申请内存空间
            outb = Marshal.AllocHGlobal((int)pwNeeded);
            Success = Win32Api.GetPrinter(handle, 2, outb, pwNeeded, out pwNeeded);
            if (!Success)
            {
                lastError = Win32Api.GetLastError();
                return Error.getPrinter;
            }
            Win32Api.PRINTER_INFO_2 info2 = new Win32Api.PRINTER_INFO_2();
            //////////////////
            //封送数据到结构体
            //////////////////
            try
            {
                info2 = (Win32Api.PRINTER_INFO_2)Marshal.PtrToStructure(outb, typeof(Win32Api.PRINTER_INFO_2));
            }
            catch (Exception ex) { Console.WriteLine(ex.Message); return Error.menory; }
            // 如果没有出错，进行解析和填充
            state = (int)info2.Status;
            if (info2.Status == 0)
            {
                // 打印机状态正常~
                Win32Api.ClosePrinter(handle);
                Marshal.FreeHGlobal(outb);
                return Error.ok;
            }

            if ((info2.Status & PRINTER_STATUS_BUSY) == PRINTER_STATUS_BUSY)
            {
                stateStr.Add("打印机正忙，请稍后再试");
            }
            if ((info2.Status & PRINTER_STATUS_DOOR_OPEN) == PRINTER_STATUS_DOOR_OPEN)
            {
                stateStr.Add("打印机舱门打开了，请联系管理员");
            }
            if ((info2.Status & PRINTER_STATUS_DRIVER_UPDATE_NEEDED) == PRINTER_STATUS_DRIVER_UPDATE_NEEDED)
            {
                stateStr.Add("打印机驱动需要升级，请联系管理员");
            }
            if ((info2.Status & PRINTER_STATUS_ERROR) == PRINTER_STATUS_ERROR)
            {
                stateStr.Add("打印机发生错误!");
            }
            if ((info2.Status & PRINTER_STATUS_INITIALIZING) == PRINTER_STATUS_INITIALIZING)
            {
                stateStr.Add("打印机正在初始化，请稍候.");
            }
            //////////////////////////

            if ((info2.Status & PRINTER_STATUS_NO_TONER) == PRINTER_STATUS_NO_TONER)
            {
                stateStr.Add("打印机墨粉不足，请联系管理员");
            }
            if ((info2.Status & PRINTER_STATUS_OFFLINE) == PRINTER_STATUS_OFFLINE)
            {
                stateStr.Add("打印机离线，请联系管理员");
            }
            if ((info2.Status & PRINTER_STATUS_OUT_OF_MEMORY) == PRINTER_STATUS_OUT_OF_MEMORY)
            {
                stateStr.Add("打印机内存不足，请联系管理员");
            }
            if ((info2.Status & PRINTER_STATUS_OUTPUT_BIN_FULL) == PRINTER_STATUS_OUTPUT_BIN_FULL)
            {
                stateStr.Add("出纸槽已满！请尽快取纸");
            }
            if ((info2.Status & PRINTER_STATUS_PAPER_JAM) == PRINTER_STATUS_PAPER_JAM)
            {
                stateStr.Add("打印机卡纸，请联系管理员");
            }
            if ((info2.Status & PRINTER_STATUS_PAPER_OUT) == PRINTER_STATUS_PAPER_OUT)
            {
                stateStr.Add("打印机缺纸，请联系管理员");
            }
            if ((info2.Status & PRINTER_STATUS_PAUSED) == PRINTER_STATUS_PAUSED)
            {
                stateStr.Add("打印机暂停");
            }
            if ((info2.Status & PRINTER_STATUS_PENDING_DELETION) == PRINTER_STATUS_PENDING_DELETION)
            {
                stateStr.Add("打印机正在初始化,请稍候再试.");
            }
            if ((info2.Status & PRINTER_STATUS_PRINTING) == PRINTER_STATUS_PRINTING)
            {
                stateStr.Add("打印机正在打印，请稍候再试");
            }
            Win32Api.ClosePrinter(handle);
            Marshal.FreeHGlobal(outb);
            return Error.printerState;
        }
        public Error getJobInfo()
        {
            return Error.ok;
        }

        /// <summary>
        /// 打印机暂停，请联系管理员
        /// </summary>
        public const int PRINTER_STATUS_PAUSED = 0x00000001;
        /// <summary>
        /// 打印机错误，请联系管理员
        /// </summary>
        public const int PRINTER_STATUS_ERROR = 0x00000002;
        /// <summary>
        /// 打印机正在删除之前的作业
        /// </summary>
        public const int PRINTER_STATUS_PENDING_DELETION = 0x00000004;
        /// <summary>
        /// 打印机卡纸，请联系管理员
        /// </summary>
        public const int PRINTER_STATUS_PAPER_JAM = 0x00000008;
        /// <summary>
        /// 打印机缺纸，请联系管理员
        /// </summary>
        public const int PRINTER_STATUS_PAPER_OUT = 0x00000010;
        /// <summary>
        /// 打印机无法打印当前页面，请联系管理员
        /// </summary>
        public const int PRINTER_STATUS_MANUAL_FEED = 0x00000020;
        /// <summary>
        /// 打印机的纸有问题，请联系管理员
        /// </summary>
        public const int PRINTER_STATUS_PAPER_PROBLEM = 0x00000040;
        /// <summary>
        /// 打印机离线，请联系管理员
        /// </summary>
        public const int PRINTER_STATUS_OFFLINE = 0x00000080;
        /// <summary>
        /// 
        /// </summary>
        public const int PRINTER_STATUS_IO_ACTIVE = 0x00000100;
        /// <summary>
        /// 打印机正忙，请稍后再试
        /// </summary>
        public const int PRINTER_STATUS_BUSY = 0x00000200;
        /// <summary>
        /// 打印机正在打印
        /// </summary>
        public const int PRINTER_STATUS_PRINTING = 0x00000400;
        /// <summary>
        /// 出纸槽已满，请联系管理员
        /// </summary>
        public const int PRINTER_STATUS_OUTPUT_BIN_FULL = 0x00000800;
        /// <summary>
        /// 
        /// </summary>
        public const int PRINTER_STATUS_NOT_AVAILABLE = 0x00001000;
        /// <summary>
        /// 打印机正在等待
        /// </summary>
        public const int PRINTER_STATUS_WAITING = 0x00002000;
        /// <summary>
        /// 打印机正在打印，请稍后...
        /// </summary>
        public const int PRINTER_STATUS_PROCESSING = 0x00004000;
        /// <summary>
        /// 打印机正在初始化，请稍候...
        /// </summary>
        public const int PRINTER_STATUS_INITIALIZING = 0x00008000;
        /// <summary>
        /// 打印机温度过高，请联系管理员
        /// </summary>
        public const int PRINTER_STATUS_WARMING_UP = 0x00010000;
        /// <summary>
        /// 墨粉过低，请联系管理员。
        /// </summary>
        public const int PRINTER_STATUS_TONER_LOW = 0x00020000;
        /// <summary>
        /// 墨粉不足，请联系管理员。
        /// </summary>
        public const int PRINTER_STATUS_NO_TONER = 0x00040000;
        /// <summary>
        /// 
        /// </summary>
        public const int PRINTER_STATUS_PAGE_PUNT = 0x00080000;
        public const int PRINTER_STATUS_USER_INTERVENTION = 0x00100000;
        /// <summary>
        /// 打印机内存不足
        /// </summary>
        public const int PRINTER_STATUS_OUT_OF_MEMORY = 0x00200000;
        /// <summary>
        /// 打印机门打开了，请联系管理员
        /// </summary>
        public const int PRINTER_STATUS_DOOR_OPEN = 0x00400000;
        /// <summary>
        /// 打印机状态位置，请联系管理员
        /// </summary>
        public const int PRINTER_STATUS_SERVER_UNKNOWN = 0x00800000;
        /// <summary>
        /// 省电模式
        /// </summary>
        public const int PRINTER_STATUS_POWER_SAVE = 0x01000000;
        /// <summary>
        /// 打印机服务器离线
        /// </summary>
        public const int PRINTER_STATUS_SERVER_OFFLINE = 0x02000000;
        /// <summary>
        /// 打印机驱动需要升级
        /// </summary>
        public const int PRINTER_STATUS_DRIVER_UPDATE_NEEDED = 0x04000000;

        public static string getPrinterTradeNumber()
        {
            return DateTime.Now.ToString("yyyyMMddHHmmss")+getRandomText(4);
        }
        public static string getRandomText(int len)
        {
            string str = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
   
            StringBuilder SB = new StringBuilder();
            Random rd = new Random();
            for (int i = 0; i < len; i++)
            {
                SB.Append(str.Substring(rd.Next(0, str.Length), 1));
            }
            return SB.ToString();
        }

    }
}
